﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace ZoneEngine.Misc
{
    public class MeshLayers
    {
        public SortedList<int, int> Mesh = new SortedList<int, int>();
        public SortedList<int, int> Override = new SortedList<int, int>();

        public int Count()
        {
            return Mesh.Count;
        }

        public int GetMesh(int number)
        {
            return Mesh.ElementAt(number).Value;
        }

        public int GetOverride(int number)
        {
            return Override.ElementAt(number).Value;
        }

        public int GetKey(int number)
        {
            return Mesh.ElementAt(number).Key;
        }

        public void AddMesh(int position, int mesh, int overridetexture, int layer)
        {
            int key = (position << 16) + layer;
            if (Mesh.ContainsKey(key))
            {
                Mesh[key] = mesh;
            }
            else
            {
                Mesh.Add(key, mesh);
            }
            if (Override.ContainsKey(key))
            {
                Override[key] = overridetexture;
            }
            else
            {
                Override.Add(key, overridetexture);
            }
        }

        public void RemoveMesh(int position, int mesh, int overridetexture, int layer)
        {
            int key = (position << 16) + layer;
            try
            {
                Mesh.Remove(key);
                Override.Remove(key);
            }
            catch
            { }
        }
        public List<AOMeshs> GetMeshs()
        {

            List<AOMeshs> am = new List<AOMeshs>();
            int c = 0;
            for (c = 0; c < Mesh.Count; c++)
            {
                AOMeshs _am = new AOMeshs();
                _am.Position = Mesh.ElementAt(c).Key >> 16;
                _am.Mesh = Mesh.ElementAt(c).Value;
                _am.OverrideTexture = Override.ElementAt(c).Value;
                _am.Layer = Mesh.ElementAt(c).Key & 0xffff;
                am.Add(_am);
            }
            return am;
        }

        public AOMeshs GetMeshAtPosition(int pos)
        {
            foreach (int key in Mesh.Keys)
            {
                if ((key >> 16) == pos)
                {
                    // Just return mesh with highest priority (0 = highest)
                    AOMeshs ma = new AOMeshs();
                    ma.Layer = key & 0xffff;
                    ma.Position = key >> 16;
                    ma.Mesh = Mesh[key];
                    ma.OverrideTexture = Override[key];
                    return ma;
                }
            }
            // No mesh at this position found
            return null;
        }


        static public List<AOMeshs> GetMeshs(Character character, bool showsocial, bool socialonly)
        {
            List<AOMeshs> _meshs;
            List<AOMeshs> _socials;
            List<AOMeshs> output = new List<AOMeshs>();


            bool LeftPadVisible;
            bool RightPadVisible;
            bool DoubleLeftPad;
            bool DoubleRightPad;
            bool ShowHelmet;
            int helmetnum;
            int helmetnumsocial;

            lock (character)
            {
                _meshs = character.MeshLayer.GetMeshs();
                _socials = character.SocialMeshLayer.GetMeshs();

                int VisualFlags = character.Stats.VisualFlags.Value;
                RightPadVisible = ((VisualFlags & 0x1) > 0);
                LeftPadVisible = ((VisualFlags & 0x2) > 0);
                ShowHelmet = ((VisualFlags & 0x4) > 0);
                DoubleLeftPad = ((VisualFlags & 0x8) > 0);
                DoubleRightPad = ((VisualFlags & 0x10) > 0);

                if (!ShowHelmet)
                {
                    if (_meshs.ElementAt(0).Position == 0) // Helmet there?
                    // This probably needs to be looked at (glasses/visors)
                    {
                        if (_meshs.ElementAt(0).Mesh != character.Stats.HeadMesh.StatBaseValue) // Dont remove the head :)
                        {
                            _meshs.RemoveAt(0);
                        }
                    }

                    if (_socials.ElementAt(0).Position == 0) // Helmet there?
                    // This probably needs to be looked at (glasses/visors)
                    {
                        if (_socials.ElementAt(0).Mesh != character.Stats.HeadMesh.StatBaseValue) // Dont remove the head :)
                        {
                            _socials.RemoveAt(0);
                        }
                    }

                }
            }

            socialonly &= showsocial; // Disable socialonly flag if showsocial is false

            // preapply visual flags
            #region Applying visual flags
            if (socialonly)
            {
                _meshs.Clear();
            }
            if ((!socialonly) && (!showsocial))
            {
                _socials.Clear();
            }

            AOMeshs leftshoulder = null;
            AOMeshs rightshoulder = null;
            int rightshouldernum = -1;
            int leftshouldernum = -1;


            for (int c1 = 0; c1 < _meshs.Count; c1++)
            {
                AOMeshs m = _meshs.ElementAt(c1);
                if (m.Position == 3)
                {
                    if (!RightPadVisible)
                    {
                        _meshs.RemoveAt(c1);
                        c1--;
                        continue;
                    }
                    else
                    {
                        rightshoulder = m;
                        rightshouldernum = c1;
                    }
                }
                if (m.Position == 4)
                {
                    if (!LeftPadVisible)
                    {
                        _meshs.RemoveAt(c1);
                        c1--;
                        continue;
                    }
                    else
                    {
                        leftshouldernum = c1;
                        leftshoulder = m;
                    }
                }
            }
            if (DoubleRightPad)
            {
                if (rightshoulder != null)
                {
                    if (leftshouldernum == -1) // no left shoulder in or left pad not visible
                    {
                        AOMeshs a = new AOMeshs();
                        a.Position = 4;
                        a.Mesh = rightshoulder.Mesh;
                        a.OverrideTexture = rightshoulder.OverrideTexture;
                        a.Layer = rightshoulder.Layer;
                        _meshs.Insert(rightshouldernum + 1, a); // Insert AFTER right shoulder
                    }
                }
            }
            if (DoubleLeftPad)
            {
                if (leftshoulder != null)
                {
                    if (rightshouldernum == -1) // no left shoulder in or left pad not visible
                    {
                        AOMeshs a = new AOMeshs();
                        a.Position = 3;
                        a.Mesh = leftshoulder.Mesh;
                        a.OverrideTexture = leftshoulder.OverrideTexture;
                        a.Layer = leftshoulder.Layer;
                        _meshs.Insert(leftshouldernum, a); // Insert right before left shoulder
                    }
                }
            }
            #endregion


            AOMeshs cloth;
            AOMeshs social;

            int c = 0;
            for (c = 0; c < 7; c++)
            {
                cloth = null;
                social = null;

                foreach (AOMeshs m in _meshs)
                {
                    if (m.Position == c)
                    {
                        cloth = m;
                        break;
                    }
                }

                foreach (AOMeshs m in _socials)
                {
                    if (m.Position == c)
                    {
                        social = m;
                    }
                }

                if (social != null)
                {
                    if ((cloth != null) && (social != null))
                    {
                        // Compare layer only when both slots are set
                        if (social.Layer - 8 < cloth.Layer)
                        {
                            if (cloth.Position == 5) // Backmeshs act different
                            {
                                output.Add(cloth);
                            }
                            cloth = social;
                        }
                    }
                    else
                    {
                        if ((showsocial) || (socialonly))
                        {
                            cloth = social;
                        }
                    }

                }
                if (cloth != null)
                {
                    output.Add(cloth);
                }

            }
            return output;
        }

        #region GetLayer
        public static int GetLayer(int placement)
        {
            switch (placement)
            {
                // Equipment pages
                case 18: // Head
                    return 0;
                case 19: // Back
                    return 0;
                case 20: // Shoulders
                case 22:
                    return 4;
                case 6: // Hands (Weapons)
                case 8:
                    return 4;

                // Social page
                case 50: // Head
                    return 0;
                case 51: // Back
                    return 0;
                case 52: // Shoulders
                case 54:
                    return 4;
                case 56: // Hands (Weapons)
                case 58:
                    return 4;

                default:
                    return 0;
            }
        }
        #endregion
    }
}
